package com.yunshipei.core.manager;

import android.text.TextUtils;

import com.yunshipei.core.common.ContentValues;
import com.yunshipei.core.common.XCloudException;
import com.yunshipei.core.model.ConfigInfo;
import com.yunshipei.core.model.InjectModel;
import com.yunshipei.core.model.InterceptModel;
import com.yunshipei.core.model.OverrideRegexModel;
import com.yunshipei.core.model.RegexModel;
import com.yunshipei.core.model.XCloudAppModel;
import com.yunshipei.core.net.EnterClient;
import com.yunshipei.core.net.ServiceApi;
import com.yunshipei.core.net.convert.JsonConverterFactory;
import com.yunshipei.core.utils.FileUtils;
import com.yunshipei.core.utils.YspLogUtils;

import org.chromiun.net.GURLUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.reactivestreams.Publisher;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

public final class XCloud2Map {

    private final Object object = new Object();

    private boolean shouldLoadAdapterFromNet = false; //标记是否是传入url才下载(更新)适配包和运行时
    private int mValidCount;
    private String mAppFilePath;
    private ConfigInfo mConfigInfo;

    private List<XCloudAppModel> xCloudAppModels = new ArrayList<>();   //存储每个适配包的manifest解析信息

    private ServiceApi mServiceApi;

    private XCloud2Map() {
    }

    private static final class XCloud2MapInner {
        private static final XCloud2Map sInstance = new XCloud2Map();
    }

    public static XCloud2Map getInstance() {
        return XCloud2MapInner.sInstance;
    }

    public void init(ConfigInfo configInfo, int validCount, String appFilePath) {
        this.mConfigInfo = configInfo;
        this.mValidCount = validCount;
        this.mAppFilePath = appFilePath;
        xCloudAppModels.clear();
        parseLocalManifest();
    }

    public void init(ConfigInfo configInfo, int validCount, String appFilePath, JSONArray jsonArray) {
        this.mConfigInfo = configInfo;
        this.mValidCount = validCount;
        this.mAppFilePath = appFilePath;
        xCloudAppModels.clear();
        parseResponseManifest(jsonArray);
        this.shouldLoadAdapterFromNet = true;
    }

    //更新manifest的数据
    void updateManifestData(JSONArray jsonArray) {
        xCloudAppModels.clear();
        parseResponseManifest(jsonArray);
    }

    //解析接口返回的所有manifest
    private void parseResponseManifest(JSONArray jsonArray) {
        if (jsonArray != null) {
            int len = jsonArray.length();
            for (int i = 0; i < len; i++) {
                JSONObject jsonObject = jsonArray.optJSONObject(i);
                XCloudAppModel xCloudAppModel = parseAdapterPac(jsonObject);
                xCloudAppModels.add(xCloudAppModel);
            }
        }
    }

    //解析本地适配包所有的manifest
    private void parseLocalManifest() {
        File rootPath = new File(mAppFilePath + File.separator + ContentValues.APP_WEB_ROOT_PATH + File.separator + ContentValues.YSP_NEW_ADAPTER_PAC_PATH);
        if (rootPath.exists()) {
            for (File dir : rootPath.listFiles()) {
                if (dir.isDirectory()) {
                    File manifestFile = new File(dir, "manifest.json");
                    if (manifestFile.exists() && !manifestFile.isDirectory()) {
                        String manifestContent = FileUtils.readFile(manifestFile.getAbsolutePath());
                        JSONObject jsonObject = null;
                        try {
                            jsonObject = new JSONObject(manifestContent);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                        if (jsonObject != null) {
                            XCloudAppModel xCloudAppModel = parseAdapterPac(jsonObject);
                            xCloudAppModels.add(xCloudAppModel);
                        }
                    }
                }
            }
        }
    }

    public XCloudAppModel parseAdapterPac(JSONObject jsonObject) {
        XCloudAppModel appModule = new XCloudAppModel();
        appModule.setScope(jsonObject.optString("scope", ""));
        appModule.setName(jsonObject.optString("name", ""));
        appModule.setStartURL(jsonObject.optString("start_url", ""));
        appModule.setRuntimeVersion(jsonObject.optString("runtime_version", ""));

        //重载的url
        JSONArray overloadTempsArray = jsonObject.optJSONArray("override_urls");
        if (overloadTempsArray != null) {
            List<OverrideRegexModel> list = appModule.getOverrideModuleList();
            for (int i = 0; i < overloadTempsArray.length(); i++) {
                JSONObject obj = overloadTempsArray.optJSONObject(i);
                if (obj == null) continue;
                OverrideRegexModel module = new OverrideRegexModel();
                module.setTargetURL(obj.optString("target_url"));
                JSONArray matcherArray = obj.optJSONArray("origin_url");
                if (matcherArray == null) continue;
                List<String> matcherList = module.getMatcherList();
                for (int j = 0; j < matcherArray.length(); j++) {
                    String ori = matcherArray.optString(j);
                    matcherList.add(ori);
                }
                list.add(module);
            }
        }

        //资源拦截规则
        JSONObject optionObj = jsonObject.optJSONObject("options");
        if (optionObj != null) {
            //忽略的资源文件
            JSONObject interceptObj = optionObj.optJSONObject("resource_intercept");
            if (interceptObj != null) {
                InterceptModel interceptModel = new InterceptModel();
                JSONArray typeArray = interceptObj.optJSONArray("type");
                if (typeArray != null && typeArray.length() > 0) {
                    List<String> types = interceptModel.getTypes();
                    for (int i = 0; i < typeArray.length(); i++) {
                        types.add(typeArray.optString(i));
                    }
                }
                JSONArray interceptMatcherObj = interceptObj.optJSONArray("ignore");
                if (interceptMatcherObj != null && interceptMatcherObj.length() > 0) {
                    List<String> interceptMatcherList = interceptModel.getIgnoreResMatcherList();
                    for (int i = 0; i < interceptMatcherObj.length(); i++) {
                        interceptMatcherList.add(interceptMatcherObj.optString(i));
                    }
                }
                appModule.setInterceptModel(interceptModel);
            }

            //需要插入的资源
            JSONArray injectResArray = optionObj.optJSONArray("resource_inject");
            if (injectResArray != null) {
                List<InjectModel> injectModels = appModule.getInjectModels();
                for (int i = 0; i < injectResArray.length(); i++) {
                    JSONObject injectObj = injectResArray.optJSONObject(i);
                    if (injectObj == null) continue;
                    String type = injectObj.optString("type");
                    String position = injectObj.optString("position");
                    String path = injectObj.optString("path");
                    InjectModel injectModel = new InjectModel(type, position, path);
                    injectModels.add(injectModel);
                }
            }

            //UserAgent
            String userAgent = optionObj.optString("user_agent");
            appModule.setUserAgent(userAgent);
        }

        //正则的适配方案
        JSONArray regexArray = jsonObject.optJSONArray("adapter_urls");
        if (regexArray != null) {
            List<RegexModel> regexModels = appModule.getRegexModelList();
            for (int j = 0; j < regexArray.length(); j++) {
                JSONObject regexObj = regexArray.optJSONObject(j);
                if (regexObj == null) continue;
                RegexModel regexModel = new RegexModel();
                regexModel.setTitle(regexObj.optString("title", ""));
                regexModel.setTargetURl(regexObj.optString("url", ""));
                JSONArray matcherList = regexObj.optJSONArray("matcher");
                if (matcherList != null) {
                    for (int k = 0; k < matcherList.length(); k++) {
                        String matResult = matcherList.optString(k, "");
                        regexModel.getMatcherList().add(matResult);
                    }
                }
                regexModels.add(regexModel);
            }
        }

        String adapterEnv = jsonObject.optString("runtime_env", "");
        if (!TextUtils.isEmpty(adapterEnv) && "1webview".equals(adapterEnv)) {
            appModule.setAdapterSupport2WebView(false);
        } else {
            appModule.setAdapterSupport2WebView(true);
        }

        //设置适配包的内容
        appModule.setManifestContent(jsonObject.toString());
        return appModule;
    }

    public void doCheck() {
        synchronized (object) {
            mValidCount--;
            if (mValidCount <= 3) {
                YspLogUtils.d("heart beat : start");
                String companyId = mConfigInfo.getCompanyId();
                long timeStamp = System.currentTimeMillis();
                String token = mConfigInfo.getToken();
                String uuid = mConfigInfo.getUuid();
                String sdkSum = getHeartBeatSdkSum(companyId, timeStamp, token, uuid);
                if (mServiceApi == null) {
                    mServiceApi = new Retrofit.Builder().client(EnterClient.getInstances().getManagerClient()).baseUrl(mConfigInfo.getUrl()).addConverterFactory(JsonConverterFactory.create()).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build().create(ServiceApi.class);
                }
                mServiceApi.heartBeat(companyId, timeStamp, token, uuid, sdkSum).flatMap(new Function<JSONObject, Publisher<Integer>>() {
                    @Override
                    public Publisher<Integer> apply(JSONObject jsonObject) throws Exception {
                        int status = jsonObject.optInt("status", -1);
                        String errorMsg = "";
                        if (status == 1) {
                            JSONObject dataObject = jsonObject.optJSONObject("data");
                            int validCount = dataObject.optInt("validCount", 0);
                            long timeStamp = dataObject.optLong("timestamp");
                            String sdkSum = dataObject.optString("sdk_sum", "");
                            JSONObject sdkSumObject = new JSONObject();
                            sdkSumObject.put("token", mConfigInfo.getToken());
                            sdkSumObject.put("count", validCount);
                            sdkSumObject.put("timestamp", timeStamp);
                            sdkSumObject.put("sdk_sum", sdkSum);
                            sdkSumObject.put("deviceId", mConfigInfo.getUuid());
                            String checkSum = GURLUtils.checkSum(sdkSumObject.toString());
                            if (!TextUtils.isEmpty(checkSum) && "check success".equalsIgnoreCase(checkSum)) {
                                return Flowable.just(validCount);
                            }
                            errorMsg = "checkSum status：" + checkSum;
                        } else {
                            errorMsg = "心跳发送失败：" + jsonObject.optString("message");
                        }
                        return Flowable.error(new XCloudException(errorMsg));
                    }
                }).subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        mValidCount = integer;
                        YspLogUtils.d("heart beat success：" + integer);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        YspLogUtils.d("heart beat failed：" + throwable.toString());
                    }
                });
            }
        }
    }

    public ConfigInfo getConfigInfo() {
        return mConfigInfo;
    }

    public List<XCloudAppModel> getXCloudAppModels() {
        return xCloudAppModels;
    }

    public boolean shouldLoadAdapterFromNet() {
        return shouldLoadAdapterFromNet;
    }

    private String getHeartBeatSdkSum(String companyId, long timeStamp, String token, String uuid) {
        JSONObject jsonObject = new JSONObject();
        try {
            jsonObject.put("sdk", companyId);
            jsonObject.put("timestamp", timeStamp);
            jsonObject.put("token", token);
            jsonObject.put("deviceId", uuid);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return GURLUtils.getSDKSum(jsonObject.toString());
    }
}